package cn.iocoder.yudao.module.contract.service.invoiceContract;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtil;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.contract.dal.dataobject.client.ClientDO;
import cn.iocoder.yudao.module.contract.dal.dataobject.company.CompanyDO;
import cn.iocoder.yudao.module.contract.dal.dataobject.contractTemplate.ContractTemplateDO;
import cn.iocoder.yudao.module.contract.dal.dataobject.frameworkAgreement.FrameworkAgreementDO;
import cn.iocoder.yudao.module.contract.dal.dataobject.invoice.InvoiceDO;
import cn.iocoder.yudao.module.contract.dal.dataobject.invoice.InvoiceDetailsDO;
import cn.iocoder.yudao.module.contract.dal.dataobject.invoice.InvoiceOrdersDO;
import cn.iocoder.yudao.module.contract.dal.dataobject.order.OrderDetailsDO;
import cn.iocoder.yudao.module.contract.dal.dataobject.orderContract.OrderContractDO;
import cn.iocoder.yudao.module.contract.dal.mysql.invoice.InvoiceDetailsMapper;
import cn.iocoder.yudao.module.contract.dal.mysql.invoice.InvoiceMapper;
import cn.iocoder.yudao.module.contract.service.client.ClientService;
import cn.iocoder.yudao.module.contract.service.company.CompanyService;
import cn.iocoder.yudao.module.contract.service.contractTemplate.ContractTemplateService;
import cn.iocoder.yudao.module.contract.service.frameworkAgreement.FrameworkAgreementService;
import cn.iocoder.yudao.module.contract.service.invoice.InvoiceOrdersService;
import cn.iocoder.yudao.module.contract.utils.HtmlToFileConverter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import cn.iocoder.yudao.module.contract.utils.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.mapstruct.ap.internal.model.assignment.UpdateWrapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import cn.iocoder.yudao.module.contract.controller.admin.invoiceContract.vo.*;
import cn.iocoder.yudao.module.contract.dal.dataobject.invoiceContract.InvoiceContractDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.contract.dal.mysql.invoiceContract.InvoiceContractMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.contract.enums.ErrorCodeConstants.*;

/**
 * 发票合同 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
@Slf4j
public class InvoiceContractServiceImpl extends ServiceImpl<InvoiceContractMapper, InvoiceContractDO> implements InvoiceContractService {

    @Resource
    private InvoiceContractMapper invoiceContractMapper;
    @Resource
    private CompanyService companyService;
    @Resource
    private ContractTemplateService contractTemplateService;
    @Resource InvoiceMapper invoiceMapper;
    @Resource
    InvoiceOrdersService invoiceOrdersService;
    @Resource
    InvoiceDetailsMapper invoiceDetailsMapper;
    @Resource
    ClientService clientService;
    @Resource
    private HtmlToFileConverter htmlToFileConverter;
    @Resource
    FrameworkAgreementService frameworkAgreementService;

    @Override
    public Long createInvoiceContract(InvoiceContractSaveReqVO createReqVO) {
        // 插入
        InvoiceContractDO invoiceContract = BeanUtils.toBean(createReqVO, InvoiceContractDO.class);
        invoiceContractMapper.insert(invoiceContract);
        // 返回
        return invoiceContract.getId();
    }

    @Override
    public void updateInvoiceContract(InvoiceContractSaveReqVO updateReqVO) {
        // 校验存在
        validateInvoiceContractExists(updateReqVO.getId());
        // 更新
        InvoiceContractDO updateObj = BeanUtils.toBean(updateReqVO, InvoiceContractDO.class);
        invoiceContractMapper.updateById(updateObj);
    }

    @Override
    public void deleteInvoiceContract(Long id) {
        // 校验存在
        validateInvoiceContractExists(id);
        // 删除
        invoiceContractMapper.deleteById(id);
    }

    private void validateInvoiceContractExists(Long id) {
        if (invoiceContractMapper.selectById(id) == null) {
            throw exception(INVOICE_CONTRACT_NOT_EXISTS);
        }
    }

    @Override
    public InvoiceContractDO getInvoiceContract(Long id) {
        return invoiceContractMapper.selectById(id);
    }

    @Override
    public PageResult<InvoiceContractPageRespVO> getInvoiceContractPage(InvoiceContractPageReqVO pageReqVO) {
        return invoiceContractMapper.selectPage(pageReqVO);
    }

    /**
     *
     * @param invoiceContract
     * @param invoiceList
     * @param type 1生成合同文件 2生成html
     */
    @Override
    public void generateContractFile(InvoiceContractDO invoiceContract,List<InvoiceDO> invoiceList,String type) {

        InvoiceDO maxInvoice = invoiceList.stream().max(Comparator.comparing(InvoiceDO::getKprq)).get();
        InvoiceDO minInvoice = invoiceList.stream().min(Comparator.comparing(InvoiceDO::getKprq)).get();

        List<Long> invoiceIds = invoiceList.stream().map(InvoiceDO::getId).collect(Collectors.toList());
        List<String> zskpIds = invoiceList.stream().map(InvoiceDO::getZskpId).collect(Collectors.toList());
        try {
            String contractNo="";
            CompanyDO company = companyService.getOne(Wrappers.<CompanyDO>lambdaQuery().eq(CompanyDO::getCompanyCode,invoiceContract.getCompanyid()));
            if(StringUtils.isBlank(invoiceContract.getContractNo())){
                if("1".equals(invoiceContract.getContractType())){
                    //公司间合同号规则：采用订单号作为合同号若重复则提交-1、-2以此内推
                    InvoiceDO invoice = invoiceMapper.selectOne(Wrappers.<InvoiceDO>lambdaQuery().in(InvoiceDO::getId,invoiceIds).likeRight(InvoiceDO::getDdh,"55").orderByAsc(InvoiceDO::getDdh),false);
                    if(invoice==null){
                        invoice = invoiceMapper.selectOne(Wrappers.<InvoiceDO>lambdaQuery().in(InvoiceDO::getId,invoiceIds).notLikeRight(InvoiceDO::getDdh,"6").notLikeRight(InvoiceDO::getDdh,"7").isNotNull(InvoiceDO::getDdh).ne(InvoiceDO::getDdh,"").orderByAsc(InvoiceDO::getDdh),false);
                    }
                    if(invoice==null){
                        throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"合同号生成失败");
                    }
                    long count = count(Wrappers.<InvoiceContractDO>lambdaUpdate().eq(InvoiceContractDO::getContractType,"1").likeRight(InvoiceContractDO::getContractNo,invoice.getDdh()));
                    if(count == 0){
                        contractNo = invoice.getDdh();
                    }else{
                        contractNo = invoice.getDdh()+"-"+count;
                    }
                }else{
                    //非公司间同号规则：LH/HS/LY/HJ/HC(公司编码)-20240701（合同签订日期）+0001（每月各公司从0001开始自动编号），例如：HS-202409080001
                    if(company==null || StringUtils.isBlank(company.getCode())){
                        throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"合同号生成失败-公司编码获取失败");
                    }
                    long count = invoiceContractMapper.countCompanyByMonth(invoiceContract.getCompanyid());
                    contractNo = company.getCode()+ (invoiceContract.getSigningDate().replaceAll("-",""))+sequenceCode(10000, count);

                }
                invoiceContract.setContractNo(contractNo);
            }
            if(StringUtils.isBlank(invoiceContract.getSigningDate())){
                if("1".equals(invoiceContract.getContractType())){
                    //公司间签订日期：最早的开票月份的一号
                    invoiceContract.setSigningDate((minInvoice.getInvoiceMonth()+"-01"));
                }else if("4".equals(invoiceContract.getContractType())){
                    List<String> ddSqkpRecordIds = invoiceList.stream().map(InvoiceDO::getDdSqkpRecordId).collect(Collectors.toList());
                    //退货协议订日期：最早的发货单过账日期
                    InvoiceOrdersDO invoiceOrders = invoiceOrdersService.getOne(Wrappers.<InvoiceOrdersDO>lambdaQuery().in(InvoiceOrdersDO::getDdSqkpRecordId,ddSqkpRecordIds).orderByAsc(InvoiceOrdersDO::getWadatLst),false);
                    invoiceContract.setSigningDate(DateUtil.format(invoiceOrders.getWadatLst(),"yyyy-MM-dd"));
                }else{
                    //其他：最早的开票日期
                    invoiceContract.setSigningDate(DateUtil.formatDate(DateUtil.parseDateTime(minInvoice.getKprq())));
                }

            }
            ContractTemplateDO contractTemplate = null;
            String contractTypeCode = "1".equals(invoiceContract.getContractType())?"F1":"4".equals(invoiceContract.getContractType())?"F3":"F2";
            if(maxInvoice.getClientCode()!=null){
                contractTemplate = contractTemplateService.getOne(Wrappers.<ContractTemplateDO>lambdaQuery().eq(ContractTemplateDO::getContractTypeCode,contractTypeCode).eq(ContractTemplateDO::getClientCode,maxInvoice.getClientCode()));
                if("2".equals(invoiceContract.getContractType()) && contractTemplate!=null){
                    invoiceContract.setContractType("3");
                }
            }
            if(contractTemplate==null){
                contractTemplate = contractTemplateService.getOne(Wrappers.<ContractTemplateDO>lambdaQuery().eq(ContractTemplateDO::getContractTypeCode,contractTypeCode).isNull(ContractTemplateDO::getClientId));
            }
            if(contractTemplate==null){
                throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"合同模板不存在");
            }
            ContractTemplateDO template1 = null;
            ContractTemplateDO template2 = null;
            if("F2".equals(contractTemplate.getContractTypeCode())){
                //发票购销合同需添加附件
                template1 = contractTemplateService.getOne(Wrappers.<ContractTemplateDO>lambdaQuery().eq(ContractTemplateDO::getContractTypeCode,"F2-1").eq(ContractTemplateDO::getClientCode,maxInvoice.getClientCode()));
                if(template1==null){
                    template1 = contractTemplateService.getOne(Wrappers.<ContractTemplateDO>lambdaQuery().eq(ContractTemplateDO::getContractTypeCode,"F2-1").isNull(ContractTemplateDO::getClientId));
                }
                if(template1==null){
                    throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"发票明细附件模板不存在");
                }
                template2 = contractTemplateService.getOne(Wrappers.<ContractTemplateDO>lambdaQuery().eq(ContractTemplateDO::getContractTypeCode,"F2-2").eq(ContractTemplateDO::getClientCode,maxInvoice.getClientCode()));
                if(template2==null){
                    template2 = contractTemplateService.getOne(Wrappers.<ContractTemplateDO>lambdaQuery().eq(ContractTemplateDO::getContractTypeCode,"F2-2").isNull(ContractTemplateDO::getClientId));
                }
                if(template2==null){
                    throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"借贷项附件模板不存在");
                }
            }
            invoiceContract.setContractTemplateId(contractTemplate.getId());
            invoiceContract.setContractTemplateName(contractTemplate.getContractName());
            ClientDO clientDO = null;
            if(StringUtils.isNotBlank(invoiceContract.getClientCode())){
                clientDO = clientService.getOne(Wrappers.<ClientDO>lambdaQuery().eq(ClientDO::getClientCode,invoiceContract.getClientCode()),false);
                if(clientDO==null){
                    throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"未找到购方"+invoiceContract.getClientCode()+"的客户信息");
                }
            }else{
                clientDO = clientService.getOne(Wrappers.<ClientDO>lambdaQuery().eq(ClientDO::getClientName,invoiceContract.getGfmc()),false);
                if(clientDO==null){
                    throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"未找到购方"+invoiceContract.getGfmc()+"的客户信息");
                }
            }
            if(StringUtils.isBlank(invoiceContract.getClientCode())){
                invoiceContract.setClientCode(clientDO.getClientCode());
            }

            List<InvoiceDetailsDO> invoiceDetailsList = invoiceDetailsMapper.selectList(new LambdaQueryWrapper<InvoiceDetailsDO>().in(InvoiceDetailsDO::getZskpId, zskpIds).ne("F2".equals(contractTemplate.getContractTypeCode()),InvoiceDetailsDO::getSl,""));
            Map<String, List<InvoiceDetailsDO>> invoiceDetails = invoiceDetailsList.stream().collect(Collectors.groupingBy(item -> item.getGgxh() + "-" + MoneyUtil.toSeparator(item.getHsdj())));
            //借贷项数据
            Map<String, List<InvoiceDetailsDO>> loanItems = new HashMap<>();
            if("F2".equals(contractTemplate.getContractTypeCode())){
                for(InvoiceDO invoiceDO : invoiceList){
                    List<InvoiceDetailsDO> invoiceDetailList = invoiceDetailsMapper.selectList(new LambdaQueryWrapper<InvoiceDetailsDO>().eq(InvoiceDetailsDO::getZskpId, invoiceDO.getZskpId()).eq(InvoiceDetailsDO::getSl,""));
                    if(invoiceDetailList.size()>0){
                        loanItems.put(invoiceDO.getFphm(),invoiceDetailList);
                    }
                }
            }


            String frameworkAgreementNo = "";
            Long frameworkAgreementId = null;
            if("2".equals(invoiceContract.getContractType()) || "3".equals(invoiceContract.getContractType())){
                FrameworkAgreementDO frameworkAgreementDO = frameworkAgreementService.getOne(Wrappers.<FrameworkAgreementDO>lambdaQuery()
                        .eq(FrameworkAgreementDO::getClientName,clientDO.getClientName())
                        .ge(FrameworkAgreementDO::getAgreementEndDate,minInvoice.getAudat())
                        .le(FrameworkAgreementDO::getAgreementStartDate,minInvoice.getAudat()),false);
                if(frameworkAgreementDO!=null){
                    frameworkAgreementNo = frameworkAgreementDO.getContractNo();
                    frameworkAgreementId = frameworkAgreementDO.getId();
                }
            }
            invoiceContract.setFrameworkAgreementId(frameworkAgreementId);

            Map<String,Object> param = buildContractParam(invoiceContract,invoiceDetails,company,clientDO,frameworkAgreementNo,invoiceList,loanItems);
            StringBuilder htmlContent = new StringBuilder(contractTemplate.getContractContent());
            htmlContent = new StringBuilder(htmlInit(htmlContent.toString()));
            htmlContent = new StringBuilder(HtmlToFileConverter.authHtmlToPdf(htmlContent.toString(), param));
            String fileUrl = null;
            if("F2".equals(contractTemplate.getContractTypeCode())){
                //销购发票需要拼接附件
                List<String> htmlContents = new ArrayList<>();
                htmlContents.add(htmlContent.toString());
                htmlContents.add(generateAttachmentHtml(template1,param));
                if(loanItems.size()>0){
                    htmlContents.add(generateAttachmentHtml(template2,param));
                }
                if("1".equals(type)){
                    fileUrl = htmlToFileConverter.htmlToWord(htmlContents,"invoiceContract/"+invoiceContract.getContractNo(),"fpht-");
                }
//                htmlContent = new StringBuilder();
                for(int i=0;i<htmlContents.size();i++){
                    if(i>0){
                        String html = htmlContents.get(i);
                        htmlContent.append("<div style='break-after: page;'></div><div class='page-break'>").append(html).append("</div>");
                    }
                }
//                htmlContent = StringUtils.join(htmlContents,"<div style='break-after: page;'></div><div class='page-break'>")+"</div>";
            }else{
                if("1".equals(type)) {
                    fileUrl = htmlToFileConverter.htmlToWord(htmlContent.toString(), "invoiceContract/" + invoiceContract.getContractNo(), "fpht-");
                }
            }

            invoiceContract.setGeneratedTime(LocalDateTime.now());
            invoiceContract.setContractHtml(htmlContent.toString());
            invoiceContract.setContractFileUrl(fileUrl);
            invoiceContract.setStatus("1");
            invoiceContract.setAbnormalCause("");
        }catch (ServiceException e){
            invoiceContract.setStatus("0");
            invoiceContract.setAbnormalCause("合同生成失败："+e.getMessage());
            log.error("合同生成失败-{}:",invoiceContract.getId(),e);
        }catch (Exception e){
            invoiceContract.setStatus("0");
            invoiceContract.setAbnormalCause("合同生成失败：系统异常");
            log.error("合同生成失败-{}:",invoiceContract.getId(),e);
        }
    }

    private String generateAttachmentHtml(ContractTemplateDO template,Map<String,Object> param)throws Exception {
        if("F2-1".equals(template.getContractTypeCode())){
            String htmlContent = "";
            htmlContent = invoiceListHtmlInit(template.getContractContent());
            htmlContent = HtmlToFileConverter.authHtmlToPdf(htmlContent, param);
            return htmlContent;
        }
        if("F2-2".equals(template.getContractTypeCode())){
            String htmlContent = "";
            htmlContent = loanItemHtmlInit(template.getContractContent());
            htmlContent = HtmlToFileConverter.authHtmlToPdf(htmlContent, param);
            return htmlContent;
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancellation(InvoiceContractDO invoiceContract,List<InvoiceDO> invoiceList) {
        invoiceContract.setStatus("2");
        invoiceContract.setContractHtml("");
        invoiceContract.setContractFileUrl("");
        updateById(invoiceContract);
        List<Long> ids = invoiceList.stream().map(InvoiceDO::getId).collect(Collectors.toList());
        invoiceMapper.update(Wrappers.<InvoiceDO>update().setSql(" contract_id = {0} ,contract_no = {1},contract_generated_time = {2},status={3}",null,null,null,"2").in("id",ids));
        invoiceMapper.updateInvalidInvoice();

    }

    private Map<String, Object> buildContractParam(InvoiceContractDO invoiceContract, Map<String, List<InvoiceDetailsDO>> invoiceDetails, CompanyDO companyDO, ClientDO clientDO,String frameworkAgreementNo,List<InvoiceDO> invoiceList,Map<String, List<InvoiceDetailsDO>> loanItems) {
        Map<String,Object> param = new HashMap<>();
        //订单信息
        param.put("购方名称", StringUtils.nvl(invoiceContract.getGfmc(), ""));
        param.put("客户编码", StringUtils.nvl(invoiceContract.getClientCode(), ""));
        param.put("销售方名称", StringUtils.nvl(invoiceContract.getXfmc(), ""));
        param.put("公司编码", StringUtils.nvl(invoiceContract.getCompanyid(), ""));
        param.put("合同号", StringUtils.nvl(invoiceContract.getContractNo(), ""));
        param.put("签订日期", StringUtils.nvl(invoiceContract.getSigningDate(), ""));
        param.put("签订年份", (StringUtils.isNotBlank(invoiceContract.getSigningDate()) && invoiceContract.getSigningDate().length()>=10)?invoiceContract.getSigningDate().substring(0,4): "");
        param.put("签订月份", (StringUtils.isNotBlank(invoiceContract.getSigningDate()) && invoiceContract.getSigningDate().length()>=10)?invoiceContract.getSigningDate().substring(5,7): "");
        param.put("合同生成时间", StringUtils.nvl(DateUtil.format(invoiceContract.getGeneratedTime(),"yyyy-MM-dd"), ""));
        param.put("开票月", StringUtils.nvl(invoiceContract.getInvoiceMonth(), ""));
        param.put("合同总金额", StringUtils.nvl(invoiceContract.getTotalMoney(), ""));
        param.put("合同管控类型", StringUtils.nvl(invoiceContract.getZzhtgklx(), ""));
        param.put("合同管控类型描述", StringUtils.nvl(invoiceContract.getZzhtgklxms(), ""));
        param.put("运输方式", "Y".equals(invoiceContract.getVsbed())?"需方自提":"N".equals(invoiceContract.getVsbed())?"供方送货，由供方代办运输，供方承担运输费":"");
        param.put("运输方式描述", StringUtils.nvl(invoiceContract.getVsbedms(), ""));
        param.put("区域名称", StringUtils.nvl(invoiceContract.getSalesmethodname(), ""));
        param.put("雇员名称", StringUtils.nvl(invoiceContract.getQyusername(), ""));
        param.put("组织名称", StringUtils.nvl(invoiceContract.getSellertaxname(), ""));
        param.put("组织编码", StringUtils.nvl(invoiceContract.getSellertaxid(), ""));
        param.put("框架协议号", StringUtils.nvl(frameworkAgreementNo, ""));
        param.put("付款方式", "0".equals(clientDO.getZmonth())?"款到发货":"货到付款");
        param.put("框架协议名", StringUtils.isNotEmpty(frameworkAgreementNo)?"框架协议：":"");
        //产品信息
        List<Map<String,Object>> details = new ArrayList<>();
        BigDecimal quantityTotal= BigDecimal.ZERO;
        BigDecimal amountSum = BigDecimal.ZERO;
        BigDecimal noTaxAmountSum = BigDecimal.ZERO;
        BigDecimal allSeSum = BigDecimal.ZERO;
        List<InvoiceDetailsDO> invoiceDetailsList = new ArrayList<>();
        for (String key : invoiceDetails.keySet()) {
            List<InvoiceDetailsDO> detailsList = invoiceDetails.get(key);
            InvoiceDetailsDO invoiceDetailsDO = new InvoiceDetailsDO();
            BigDecimal slSum = BigDecimal.ZERO;
            BigDecimal bhsjeSum = BigDecimal.ZERO;
            BigDecimal hsjeSum = BigDecimal.ZERO;
            BigDecimal seSum = BigDecimal.ZERO;
            for(InvoiceDetailsDO detailsDO : detailsList){
                if(StringUtils.isNotBlank(detailsDO.getSl())){
                    slSum = slSum.add(new BigDecimal(detailsDO.getSl()));
                }
                if(detailsDO.getBhsje()!=null){
                    bhsjeSum = bhsjeSum.add(detailsDO.getBhsje());
                }
                if(detailsDO.getHsje()!=null){
                    hsjeSum = hsjeSum.add(detailsDO.getHsje());
                }
                if(detailsDO.getSe()!=null){
                    seSum = seSum.add(detailsDO.getSe());
                }
            }
            invoiceDetailsDO.setSpmc(detailsList.get(0).getSpmc());;
            invoiceDetailsDO.setSpbmjc(detailsList.get(0).getSpbmjc());;
            invoiceDetailsDO.setGgxh(detailsList.get(0).getGgxh());
            invoiceDetailsDO.setDw(detailsList.get(0).getDw());
            invoiceDetailsDO.setSl(slSum.toString());
            invoiceDetailsDO.setBhsdj(detailsList.get(0).getBhsdj());
            invoiceDetailsDO.setHsdj(detailsList.get(0).getHsdj());
            invoiceDetailsDO.setBhsje(bhsjeSum);
            invoiceDetailsDO.setHsje(hsjeSum);
            invoiceDetailsDO.setSe(seSum);
            invoiceDetailsDO.setSv(detailsList.get(0).getSv());

            invoiceDetailsList.add(invoiceDetailsDO);
        }

        for(int i=0;i<invoiceDetailsList.size();i++){
            InvoiceDetailsDO invoiceDetailsDO = invoiceDetailsList.get(i);
            Map<String,Object> data = new HashMap<>();
            data.put("序号",i+1);
            data.put("商品名称", StringUtils.nvl(invoiceDetailsDO.getSpmc(),""));
            data.put("商品编码简称", StringUtils.nvl(invoiceDetailsDO.getSpbmjc(),""));
            data.put("规格型号", StringUtils.nvl(invoiceDetailsDO.getGgxh(),""));
            data.put("单位", StringUtils.nvl(invoiceDetailsDO.getDw(),""));
            data.put("含税单价", StringUtils.nvl(MoneyUtil.toSeparator(invoiceDetailsDO.getHsdj()),""));
            data.put("不含税单价", StringUtils.nvl(MoneyUtil.toSeparator(invoiceDetailsDO.getBhsdj()),""));
            data.put("数量", StringUtils.nvl(MoneyUtil.toSeparator(invoiceDetailsDO.getSl()),""));
            data.put("含税金额", StringUtils.nvl(MoneyUtil.toSeparator(invoiceDetailsDO.getHsje().toString()),""));
            data.put("不含税金额", StringUtils.nvl(MoneyUtil.toSeparator(invoiceDetailsDO.getBhsje().toString()),""));
            data.put("税率", StringUtils.nvl(MoneyUtil.toSeparator(invoiceDetailsDO.getSv()),""));
            data.put("税额", StringUtils.nvl(MoneyUtil.toSeparator(invoiceDetailsDO.getSe().toString()),""));

            if(StringUtils.isNotBlank(invoiceDetailsDO.getSl())){
                quantityTotal = quantityTotal .add(new BigDecimal(invoiceDetailsDO.getSl()));
            }
            if(invoiceDetailsDO.getHsje()!=null){
                amountSum = amountSum.add(invoiceDetailsDO.getHsje());
            }
            if(invoiceDetailsDO.getBhsje()!=null){
                noTaxAmountSum = noTaxAmountSum.add(invoiceDetailsDO.getBhsje());
            }
            if(invoiceDetailsDO.getSe()!=null){
                allSeSum = allSeSum.add(invoiceDetailsDO.getSe());
            }
            details.add(data);
        }
        param.put("invoiceDetails",details);


        List<Map<String,Object>> invoices = new ArrayList<>();
        for(int i=0;i<invoiceList.size();i++){
            InvoiceDO invoiceDO = invoiceList.get(i);
            Map<String,Object> data = new HashMap<>();
            data.put("序号",i+1);
            data.put("明细合同编号", StringUtils.nvl(invoiceContract.getContractNo(),""));
            data.put("明细发票号码", StringUtils.nvl(invoiceDO.getFphm(),""));
            data.put("明细金额", StringUtils.nvl(MoneyUtil.toSeparator(invoiceDO.getJshj()),""));
            data.put("明细开票日期", StringUtils.nvl(invoiceDO.getKprq(),""));
            invoices.add(data);
        }
        param.put("invoiceList",invoices);

        List<Map<String,Object>> loanItem = new ArrayList<>();
        BigDecimal jeSum = BigDecimal.ZERO;
        for (String key : loanItems.keySet()) {
            List<InvoiceDetailsDO> detailsList = loanItems.get(key);
            Map<String,Object> data = new HashMap<>();
            for(InvoiceDetailsDO detailsDO : detailsList){
                if(detailsDO.getHsje()!=null){
                    jeSum = jeSum.add(detailsDO.getHsje());
                }
                data.put("借贷项发票号码",key);
                data.put("借贷项金额",StringUtils.nvl(MoneyUtil.toSeparator(detailsDO.getHsje().toString()),""));
                data.put("借贷项类型",(detailsDO.getHsje()!=null && detailsDO.getHsje().compareTo(BigDecimal.ZERO) >0)?"补差价":"折扣");
                loanItem.add(data);
            }
        }
        param.put("loanItem",loanItem);
        param.put("借贷项总金额",StringUtils.nvl(MoneyUtil.toSeparator(String.valueOf(jeSum)), ""));


        //产品合计
        param.put("数量合计",MoneyUtil.toSeparator(quantityTotal.toString()));
        param.put("不含税总金额合计", StringUtils.nvl(MoneyUtil.toSeparator(noTaxAmountSum.toString()), ""));
        param.put("含税金额合计", StringUtils.nvl(MoneyUtil.toSeparator(amountSum.toString()), ""));
        param.put("税额合计", StringUtils.nvl(MoneyUtil.toSeparator(allSeSum.toString()), ""));
        param.put("合计金额大写", StringUtils.nvl(MoneyUtil.toChinese(String.valueOf(amountSum)), ""));
        //公司信息（乙方）
        param.put("供方单位名称", StringUtils.nvl(companyDO.getCompanyName(), ""));
        param.put("供方单位地址", StringUtils.nvl(companyDO.getAddress(), ""));
        param.put("供方法定代表", StringUtils.nvl(companyDO.getLegalPerson(), ""));
        param.put("供方电话", StringUtils.nvl(companyDO.getPhone(), ""));
        param.put("供方传真", StringUtils.nvl(companyDO.getFaxes(), ""));
        param.put("供方开户银行", StringUtils.nvl(companyDO.getBankName(), ""));
        param.put("供方账号", StringUtils.nvl(companyDO.getBankAccount(), ""));
        param.put("供方税号", StringUtils.nvl(companyDO.getTaxNumber(), ""));
        param.put("签订地点", StringUtils.nvl(companyDO.getSigningAddress(), ""));
        //客户信息（甲方）

        param.put("客户名称", StringUtils.nvl(clientDO.getClientName(), ""));
        param.put("客户简称", StringUtils.nvl(clientDO.getCalledForShort(), ""));
        param.put("客户电话", StringUtils.nvl(clientDO.getPhone(), ""));
        param.put("客户传真", StringUtils.nvl(clientDO.getFaxes(), ""));
        param.put("客户街道", StringUtils.nvl(clientDO.getStreet(), ""));
        param.put("客户法定代表", StringUtils.nvl(clientDO.getLegalPerson(), ""));
        param.put("客户委托代表", StringUtils.nvl(clientDO.getProxy(), ""));
        param.put("客户开户银行", StringUtils.nvl(clientDO.getBankName(), ""));
        param.put("客户开户账号", StringUtils.nvl(clientDO.getBankAccount(), ""));
        param.put("客户QQ", StringUtils.nvl(clientDO.getQqNumber(), ""));
        param.put("客户微信", StringUtils.nvl(clientDO.getWeChatNumber(), ""));
        param.put("客户收票地址", StringUtils.nvl(clientDO.getCollectionAddress(), ""));
        param.put("客户接收人姓名", StringUtils.nvl(clientDO.getReceiverName(), ""));
        param.put("客户接收人职务", StringUtils.nvl(clientDO.getReceiverDuty(), ""));
        param.put("客户接收人电话", StringUtils.nvl(clientDO.getReceiverPhone(), ""));
        param.put("街道2", StringUtils.nvl(clientDO.getStrSuppl1(), ""));
        param.put("街道3", StringUtils.nvl(clientDO.getStrSuppl2(), ""));
        return param;
    }


    /**
     * 处理富文本html
     * @param htmlContent
     * @return
     */
    private String htmlInit(String htmlContent) {
        htmlContent= htmlContent.replaceAll("\\$\\{序号}","\\$\\{invoiceDetail.序号}");
        htmlContent= htmlContent.replaceAll("\\$\\{商品名称}","\\$\\{invoiceDetail.商品名称}");
        htmlContent= htmlContent.replaceAll("\\$\\{商品编码简称}","\\$\\{invoiceDetail.商品编码简称}");
        htmlContent= htmlContent.replaceAll("\\$\\{规格型号}","\\$\\{invoiceDetail.规格型号}");
        htmlContent= htmlContent.replaceAll("\\$\\{单位}","\\$\\{invoiceDetail.单位}");
        htmlContent= htmlContent.replaceAll("\\$\\{含税单价}","\\$\\{invoiceDetail.含税单价}");
        htmlContent= htmlContent.replaceAll("\\$\\{不含税单价}","\\$\\{invoiceDetail.不含税单价}");
        htmlContent= htmlContent.replaceAll("\\$\\{数量}","\\$\\{invoiceDetail.数量}");
        htmlContent= htmlContent.replaceAll("\\$\\{含税金额}","\\$\\{invoiceDetail.含税金额}");
        htmlContent= htmlContent.replaceAll("\\$\\{不含税金额}","\\$\\{invoiceDetail.不含税金额}");
        htmlContent= htmlContent.replaceAll("\\$\\{税率}","\\$\\{invoiceDetail.税率}");
        htmlContent= htmlContent.replaceAll("\\$\\{税额}","\\$\\{invoiceDetail.税额}");

//        htmlContent= htmlContent.replaceAll("\\$\\{数量合计}","\\$\\{invoiceDetail.数量合计}");
//        htmlContent= htmlContent.replaceAll("\\$\\{不含税总金额合计}","\\$\\{invoiceDetail.不含税总金额合计}");
//        htmlContent= htmlContent.replaceAll("\\$\\{含税金额合计}","\\$\\{invoiceDetail.含税金额合计}");
//        htmlContent= htmlContent.replaceAll("\\$\\{合计金额大写}","\\$\\{invoiceDetail.合计金额大写}");

//        htmlContent = addWatermark(htmlContent);
        Document doc = Jsoup.parse(htmlContent);
        Elements tdElements =  doc.select("td");
        for (Element cell : tdElements) {
            String text = cell.text(); // 获取td元素及其所有子元素的文本内容
            if (text.startsWith("${invoiceDetail")) {
                Element tr = cell.parent(); // 获取单元格的父元素
                if (tr.tagName().equals("tr")) { // 确保父元素是tr
                    Element trr = tr.parent(); // 获取单元格的父元素
                    if(!trr.tagName().equals("list")) {
                        // 创建<#list></#list>元素
                        tr.wrap("<list>");
                    }
                }
            }
        }

        htmlContent = doc.html();
        htmlContent = htmlContent.replaceAll("<list>","<#list invoiceDetails as invoiceDetail>");
        htmlContent = htmlContent.replaceAll("</list>","</#list>");
        return htmlContent;
    }


    private String invoiceListHtmlInit(String htmlContent) {
        htmlContent= htmlContent.replaceAll("\\$\\{序号}","\\$\\{invoice.序号}");
        htmlContent= htmlContent.replaceAll("\\$\\{明细合同编号}","\\$\\{invoice.明细合同编号}");
        htmlContent= htmlContent.replaceAll("\\$\\{明细发票号码}","\\$\\{invoice.明细发票号码}");
        htmlContent= htmlContent.replaceAll("\\$\\{明细金额}","\\$\\{invoice.明细金额}");
        htmlContent= htmlContent.replaceAll("\\$\\{明细开票日期}","\\$\\{invoice.明细开票日期}");


//        htmlContent = addWatermark(htmlContent);
        Document doc = Jsoup.parse(htmlContent);
        Elements tdElements =  doc.select("td");
        for (Element cell : tdElements) {
            String text = cell.text(); // 获取td元素及其所有子元素的文本内容
            if (text.startsWith("${invoice.")) {
                Element tr = cell.parent(); // 获取单元格的父元素
                if (tr.tagName().equals("tr")) { // 确保父元素是tr
                    Element trr = tr.parent(); // 获取单元格的父元素
                    if(!trr.tagName().equals("list")) {
                        // 创建<#list></#list>元素
                        tr.wrap("<list>");
                    }
                }
            }
        }

        htmlContent = doc.html();
        htmlContent = htmlContent.replaceAll("<list>","<#list invoiceList as invoice>");
        htmlContent = htmlContent.replaceAll("</list>","</#list>");
        return htmlContent;
    }


    private String loanItemHtmlInit(String htmlContent) {
        htmlContent= htmlContent.replaceAll("\\$\\{序号}","\\$\\{item.序号}");
        htmlContent= htmlContent.replaceAll("\\$\\{借贷项发票号码}","\\$\\{item.借贷项发票号码}");
        htmlContent= htmlContent.replaceAll("\\$\\{借贷项金额}","\\$\\{item.借贷项金额}");
        htmlContent= htmlContent.replaceAll("\\$\\{借贷项类型}","\\$\\{item.借贷项类型}");

//        htmlContent= htmlContent.replaceAll("\\$\\{数量合计}","\\$\\{invoiceDetail.数量合计}");
//        htmlContent= htmlContent.replaceAll("\\$\\{不含税总金额合计}","\\$\\{invoiceDetail.不含税总金额合计}");
//        htmlContent= htmlContent.replaceAll("\\$\\{含税金额合计}","\\$\\{invoiceDetail.含税金额合计}");
//        htmlContent= htmlContent.replaceAll("\\$\\{合计金额大写}","\\$\\{invoiceDetail.合计金额大写}");

//        htmlContent = addWatermark(htmlContent);
        Document doc = Jsoup.parse(htmlContent);
        Elements tdElements =  doc.select("td");
        for (Element cell : tdElements) {
            String text = cell.text(); // 获取td元素及其所有子元素的文本内容
            if (text.startsWith("${item.")) {
                Element tr = cell.parent(); // 获取单元格的父元素
                if (tr.tagName().equals("tr")) { // 确保父元素是tr
                    Element trr = tr.parent(); // 获取单元格的父元素
                    if(!trr.tagName().equals("list")) {
                        // 创建<#list></#list>元素
                        tr.wrap("<list>");
                    }
                }
            }
        }

        htmlContent = doc.html();
        htmlContent = htmlContent.replaceAll("<list>","<#list loanItem as item>");
        htmlContent = htmlContent.replaceAll("</list>","</#list>");
        return htmlContent;
    }

    public static String sequenceCode(Integer maxNum, Long count) {  // 如生成001这种，maxNum为1000  0001的话maxNum则为10000，count则是我们从数据库中查询的总数

        String strNum = String.valueOf(maxNum + count);
        if (StringUtils.isEmpty(strNum) || 1 == strNum.length()) {
            return "";
        }
        return strNum.substring(1);
    }

}